const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");
const { rimraf, rimrafSync } = require("rimraf");
// 在 index.js 中更新可能的目录列表
const BUILD_OUTPUT_DIRS = [
  "dist", // Vite/Vue/React 默认
  "build", // Create-React-App 默认
  "out", // Next.js 默认
  "public", // 某些静态站点
  "output", // 其他框架
  "release", // 自定义配置
];
module.exports = {
  installAndBuild: async function (buildDir) {
    try {
      console.log("进入构建目录:", buildDir);
      process.chdir(buildDir);

      // 检查package.json
      if (!fs.existsSync("package.json")) {
        throw new Error("package.json 不存在");
      }

      // 安装依赖
      console.log("安装依赖...");
      execSync("npm install --force", { stdio: "inherit" });

      // 执行构建
      console.log("执行构建...");
      execSync("npm run build", { stdio: "inherit" });
    } catch (error) {
      throw new Error(`构建失败: ${error.message}`);
    } finally {
      // 返回原目录
      process.chdir(__dirname);
    }
  },
  // 统一删除方法
  deleteDirectory: async function (directory, options = {}) {
    const maxRetries = options.maxRetries || 5;
    const retryDelay = options.retryDelay || 1000;

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        // 方法1: 使用rimraf异步删除
        await rimraf(directory, {
          maxRetries: 3,
          emfileWait: 1000,
          glob: false,
        });

        // 验证是否删除成功
        if (!fs.existsSync(directory)) return;

        // 方法2: Windows系统命令
        if (process.platform === "win32") {
          try {
            // 杀死可能占用文件的进程
            execSync(`taskkill /F /IM node.exe /T`, { stdio: "ignore" });
            execSync(`rd /s /q "${path.resolve(directory)}"`, {
              stdio: "ignore",
            });
          } catch (winErr) {
            console.warn(`Windows命令删除失败: ${winErr.message}`);
          }
        }

        // 方法3: 终极方案 - 重命名后删除
        if (fs.existsSync(directory)) {
          const tempDir = `${directory}_deleteme_${Date.now()}`;
          fs.renameSync(directory, tempDir);
          await rimraf(tempDir);
        }

        return;
      } catch (error) {
        if (attempt === maxRetries) {
          throw new Error(`无法删除目录 ${directory}: ${error.message}`);
        }
        await new Promise((resolve) =>
          setTimeout(resolve, retryDelay * attempt)
        );
      }
    }
  },

  // 优化后的克隆方法
  cloneRepo: async function (repoUrl, buildDir) {
    const maxCloneAttempts = 3;

    for (let attempt = 1; attempt <= maxCloneAttempts; attempt++) {
      try {
        console.log(
          `[尝试 ${attempt}/${maxCloneAttempts}] 克隆到: ${buildDir}`
        );

        // 清理目标目录（使用绝对路径）
        if (fs.existsSync(buildDir)) {
          console.log("清理现有目录...");
          await this.deleteDirectory(path.resolve(buildDir));
        }

        // 执行克隆（显示完整命令）
        const cmd = `git clone ${repoUrl} "${path.resolve(buildDir)}"`;
        console.log(`执行: ${cmd}`);
        execSync(cmd, {
          stdio: "inherit",
          timeout: 60000,
          cwd: path.dirname(buildDir), // 在父目录执行
        });

        // 严格验证
        const gitDir = path.join(buildDir, ".git");
        if (!fs.existsSync(gitDir)) {
          throw new Error(".git目录未创建");
        }

        console.log(`验证: ${buildDir} 创建成功`);
        return;
      } catch (error) {
        if (attempt === maxCloneAttempts) {
          throw new Error(
            `克隆失败: ${error.message}\n最后尝试删除残留目录...`
          );
        }
        await new Promise((resolve) => setTimeout(resolve, 2000 * attempt));
      }
    }
  },

  // 优化后的拷贝方法
  copyBuildResult: async function (buildDir, targetDir) {
    console.log("开始拷贝构建结果...");
    // 1. 验证构建目录存在
    if (!fs.existsSync(buildDir)) {
      throw new Error(`构建目录不存在: ${buildDir}\n请先完成克隆和构建步骤`);
    }
    // 深度查找构建目录
    const findBuildDir = (dir) => {
      const candidates = BUILD_OUTPUT_DIRS.map((d) => path.join(dir, d));
      for (const candidate of candidates) {
        if (fs.existsSync(candidate)) return candidate;
      }

      // 递归查找子目录
      const subdirs = fs
        .readdirSync(dir, { withFileTypes: true })
        .filter((dirent) => dirent.isDirectory())
        .map((dirent) => path.join(dir, dirent.name));

      for (const subdir of subdirs) {
        const result = findBuildDir(subdir);
        if (result) return result;
      }

      return null;
    };

    const buildOutputDir = findBuildDir(buildDir);

    if (!buildOutputDir) {
      // 打印目录结构帮助调试
      console.error("项目目录结构:");
      execSync(`tree "${buildDir}" /F /A`, { stdio: "inherit" });
      throw new Error(
        `未找到构建输出目录，请检查构建是否成功。搜索了: ${BUILD_OUTPUT_DIRS.join(
          ", "
        )}`
      );
    }

    console.log(`找到构建输出目录: ${buildOutputDir}`);

    // 处理目标目录
    if (fs.existsSync(targetDir)) {
      const backupDir = `${targetDir}_backup_${Date.now()}`;
      console.log(`备份现有目录到: ${backupDir}`);

      try {
        // 尝试直接重命名
        fs.renameSync(targetDir, backupDir);
      } catch (error) {
        // 回退到复制+删除
        console.warn("直接重命名失败，采用复制备份方案");
        await this.copyDirectory(buildOutputDir, backupDir);
        await this.deleteDirectory(targetDir);
      }
    }

    // 执行拷贝
    await this.copyDirectory(buildOutputDir, targetDir);
    console.log("构建结果拷贝完成！");
  },
  // 更新 cleanup 方法
  cleanup: async function (buildDir) {
    console.log("开始清理临时文件...");
    await this.forceUnlockAndDelete(buildDir);
    console.log("清理完成");
  },

  forceUnlockAndDelete: async function (dir) {
    try {
      // 方法1: 使用 rimraf
      await rimraf(dir, { maxBusyTries: 5 });

      // 方法2: Windows 专用解锁
      if (process.platform === "win32") {
        try {
          // 解锁文件句柄
          execSync(
            `handle64.exe "${path.resolve(
              dir
            )}" -nobanner -accepteula -c > nul && ` +
              `for /f "tokens=3,6" %a in ('handle64.exe "${path.resolve(
                dir
              )}" -nobanner -accepteula') do ` +
              `taskkill /pid %b /f`,
            { stdio: "ignore" }
          );

          // 强制删除
          execSync(`rd /s /q "${path.resolve(dir)}"`, { stdio: "ignore" });
        } catch {}
      }

      // 方法3: 终极方案 - 重命名后删除
      if (fs.existsSync(dir)) {
        const tempDir = `${dir}_trash_${Date.now()}`;
        fs.renameSync(dir, tempDir);
        setTimeout(() => rimraf(tempDir), 3000);
      }
    } catch (error) {
      console.error("最终删除失败，请手动删除目录:", dir);
    }
  },
  // 改进的递归拷贝方法
  copyDirectory: async function (src, dest) {
    if (!fs.existsSync(src)) {
      throw new Error(`源目录不存在: ${src}`);
    }

    // 确保目标目录存在
    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest, { recursive: true });
    }

    const entries = fs.readdirSync(src, { withFileTypes: true });

    await Promise.all(
      entries.map(async (entry) => {
        const srcPath = path.join(src, entry.name);
        const destPath = path.join(dest, entry.name);

        if (entry.isDirectory()) {
          await this.copyDirectory(srcPath, destPath);
        } else {
          // 使用流式拷贝处理大文件
          await new Promise((resolve, reject) => {
            const readStream = fs.createReadStream(srcPath);
            const writeStream = fs.createWriteStream(destPath);

            readStream.on("error", reject);
            writeStream.on("error", reject);
            writeStream.on("finish", resolve);

            readStream.pipe(writeStream);
          });
        }
      })
    );
  },
};
